Loading In the Data
emdat_old <- read_csv('~/Desktop/projects/emdat_proj/full_emdat_geocoded_finally.csv')
Warning: One or more parsing issues, call `problems()` on your data frame for details, e.g.:
dat <- vroom(...)
problems(dat)Rows: 74035 Columns: 51── Column specification ────────────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (27): Dis No, Seq, Disaster Group, Disaster Subgroup, Disaster Type, Disaster Subtype, Disaster Sub...
dbl (18): Year, Dis Mag Value, Start Year, Start Month, Start Day, End Year, End Month, End Day, Total ...
lgl (5): Glide, Aid Contribution, Reconstruction Costs ('000 US$), Admin1 Code, uncertain_location_spe...
time (1): Local Time
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
emdat_new <- read_csv('~/Desktop/projects/emdat_proj/data/geocoded_21_23_emdat.csv')
Rows: 4987 Columns: 54── Column specification ────────────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (27): Dis No, Seq, Glide, Disaster Group, Disaster Subgroup, Disaster Type, Disaster Subtype, Disast...
dbl (22): Year, Dis Mag Value, Start Year, Start Month, Start Day, End Year, End Month, End Day, Total D...
lgl (5): AID Contribution ('000 US$), Latitude, Longitude, Local Time, uncertain_location_specificity
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
ENSO data
enso_data <- read_csv('~/Desktop/projects/emdat_proj/data/enso_data_copy2.csv')
Rows: 812 Columns: 7── Column specification ────────────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr (4): MonthTxt, PeriodTxt, PeriodNum, Event
dbl (3): Year, MonthNum, Value
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
enso_data %>%
group_by(Event) %>%
count()
emdat_hydrological_enso %>%
filter(!is.na(enso_Value)) %>%
filter(!is.na(wet)) %>%
mutate(enso_positive = (enso_Value > 0)) %>%
group_by(`Dis No`) %>%
summarize(enso_pos = any(enso_positive),enso_val = mean(enso_Value), is_wet = any(wet)) %>%
ggplot(mapping = aes(x = enso_val, fill = is_wet)) +
geom_histogram(stat = "density") +
facet_grid(~is_wet) +
ggtitle("Counts of Disasters compared to value of ONI with wet disasters in Blue and Dry in Red")
Warning: Ignoring unknown parameters: `binwidth`, `bins`, and `pad`







resy <- 2.5
emdat_hydrological_enso %>%
left_join(event_num_months, by = c("Event")) %>%
filter(!is.na(enso_Value)) %>%
filter(!is.na(wet)) %>%
filter(!is.na(lat)) %>%
mutate(wet_factor = as_factor(wet)) %>%
mutate(Event_factor = fct_recode(as_factor(Event), no_event = "N", negative = "-", positive = "+")) %>%
mutate(wet_string = fct_recode(wet_factor, wet_disasters = "TRUE", dry_disasters = "FALSE")) %>%
mutate(lat_box = (as.integer(lat) %/% resy) * resy , lng_box = (as.integer(lng) %/% resy) * resy) %>%
mutate(dis_no_factor = as_factor(`Dis No`)) %>%
group_by(lat_box, lng_box, Event_factor, wet_string, dis_no_factor) %>%
summarize(num_months = first(num_months), num_disaster_month = mean(num_months_disaster)) %>%
group_by(lat_box, lng_box, Event_factor, wet_string) %>%
summarize(num_months = first(num_months), num_disaster_months = sum(num_disaster_month)) %>%
mutate(disaster_rate = num_disaster_months / num_months) %>%
pivot_wider(id_cols = c(lat_box, lng_box), names_from = c(Event_factor, wet_string), values_from = c(disaster_rate), values_fill = 0) %>%
mutate(positive_wet_relative_risk = positive_wet_disasters / no_event_wet_disasters,
negative_wet_relative_risk = negative_wet_disasters / no_event_wet_disasters,
positive_dry_relative_risk = positive_dry_disasters / no_event_dry_disasters,
negative_dry_relative_risk = negative_dry_disasters / no_event_dry_disasters) %>%
select(lat_box, lng_box, positive_wet_relative_risk, negative_wet_relative_risk, positive_dry_relative_risk, negative_dry_relative_risk) %>%
pivot_longer(cols = c(positive_wet_relative_risk, negative_wet_relative_risk, positive_dry_relative_risk, negative_dry_relative_risk), names_to = 'risk', values_to = 'value') %>%
mutate(risk_factor = as_factor(risk), values_cleaned = if_else(is.infinite(value), 18, value)) %>%
mutate(relative_risk_cleaned = if_else(is.nan(values_cleaned), 1, values_cleaned)) %>%
mutate(relative_risk_cleaned2 = if_else((relative_risk_cleaned) > 2, 2, relative_risk_cleaned)) %>%
ggplot() +
geom_sf(data = world_map) +
geom_tile(mapping = aes(x = lng_box, y = lat_box, fill = relative_risk_cleaned2, width = resy)) +
scale_fill_gradient2(midpoint = 1, limits = c(0, 2), low = 'cyan', high = 'red') +
facet_grid(rows = vars(risk_factor))+
ggtitle("Relative risk plot using calculations of the form [{num_disasters_positive_wet / num_months_positive} / {num_disasters_no_event_wet / num_months_no_event}]")
`summarise()` has grouped output by 'lat_box', 'lng_box', 'Event_factor', 'wet_string'. You can override using the `.groups` argument.`summarise()` has grouped output by 'lat_box', 'lng_box', 'Event_factor'. You can override using the `.groups` argument.

resy <- 2.5
emdat_hydrological_enso %>%
left_join(event_num_months, by = c("Event")) %>%
filter(!is.na(enso_Value)) %>%
filter(!is.na(wet)) %>%
filter(!is.na(lat)) %>%
mutate(wet_factor = as_factor(wet)) %>%
mutate(Event_factor = fct_recode(as_factor(Event), no_event = "N", negative = "-", positive = "+")) %>%
mutate(wet_string = fct_recode(wet_factor, wet_disasters = "TRUE", dry_disasters = "FALSE")) %>%
mutate(lat_box = (as.integer(lat) %/% resy) * resy , lng_box = (as.integer(lng) %/% resy) * resy) %>%
mutate(dis_no_factor = as_factor(`Dis No`)) %>%
group_by(lat_box, lng_box, Event_factor, wet_string, dis_no_factor) %>%
summarize(num_months = first(num_months), num_disaster_month = mean(num_months_disaster)) %>%
group_by(lat_box, lng_box, Event_factor, wet_string) %>%
summarize(num_months = first(num_months), num_disaster_months = sum(num_disaster_month)) %>%
mutate(disaster_rate = num_disaster_months / num_months) %>%
pivot_wider(id_cols = c(lat_box, lng_box), names_from = c(Event_factor, wet_string), values_from = c(disaster_rate), values_fill = 0) %>%
mutate(positive_wet_percent = positive_wet_disasters / (no_event_wet_disasters + positive_wet_disasters + negative_wet_disasters) ,
negative_wet_percent = negative_wet_disasters / (no_event_wet_disasters + positive_wet_disasters + negative_wet_disasters),
positive_dry_percent = positive_dry_disasters / (no_event_dry_disasters + positive_dry_disasters + negative_dry_disasters),
negative_dry_percent = negative_dry_disasters / (no_event_dry_disasters + positive_dry_disasters + negative_dry_disasters)
) %>%
select(lat_box, lng_box, positive_wet_percent, negative_wet_percent, positive_dry_percent, negative_dry_percent) %>%
pivot_longer(cols = c(positive_wet_percent, negative_wet_percent, positive_dry_percent, negative_dry_percent), names_to = 'typey', values_to = 'value') %>%
mutate(type_factor = as_factor(typey), values = if_else(is.nan(value), 0, value)) %>%
ggplot() +
geom_sf(data = world_map) +
geom_tile(mapping = aes(x = lng_box, y = lat_box, fill = values, width = resy)) +
scale_fill_gradient(low = 'white', high = 'red') +
facet_grid(rows = vars(type_factor))+
ggtitle("Disaster Percent plot using calculations of the form [positive_wet / all_wet]")
`summarise()` has grouped output by 'lat_box', 'lng_box', 'Event_factor', 'wet_string'. You can override using the `.groups` argument.`summarise()` has grouped output by 'lat_box', 'lng_box', 'Event_factor'. You can override using the `.groups` argument.

# SPLIT YEAR INTO 2
# Apr to Sep
# Oct to Mar
## calculate relative risk within each box
### create boxes acc to resy X resy
resy <- 2.5
event_half_num_months <- enso_data %>%
mutate(spring_summery = as_factor((MonthNum >= 4) & (MonthNum <= 9))) %>%
mutate(half_year = fct_recode(spring_summery, spring_summer = "TRUE", fall_winter = "FALSE")) %>%
group_by(Event, half_year) %>%
summarize(num_months = n())
`summarise()` has grouped output by 'Event'. You can override using the `.groups` argument.
emdat_hydrological_enso %>%
mutate(spring_summery = as_factor((end_month >= 4) & (end_month <= 9))) %>%
mutate(half_year = fct_recode(spring_summery, spring_summer = "TRUE", fall_winter = "FALSE")) %>%
left_join(event_half_num_months, by = c("Event", "half_year")) %>%
filter(!is.na(enso_Value)) %>%
filter(!is.na(wet)) %>%
filter(!is.na(lat)) %>%
mutate(wet_factor = as_factor(wet)) %>%
mutate(Event_factor = fct_recode(as_factor(Event), no_event = "N", negative = "-", positive = "+")) %>%
mutate(wet_string = fct_recode(wet_factor, wet_disasters = "TRUE", dry_disasters = "FALSE")) %>%
mutate(lat_box = (as.integer(lat) %/% resy) * resy , lng_box = (as.integer(lng) %/% resy) * resy) %>%
mutate(dis_no_factor = as_factor(`Dis No`)) %>%
group_by(lat_box, lng_box, Event_factor, wet_string, dis_no_factor, half_year) %>%
summarize(num_months = first(num_months), num_disaster_month = mean(num_months_disaster)) %>%
group_by(lat_box, lng_box, Event_factor, wet_string, half_year) %>%
summarize(num_months = first(num_months), num_disaster_months = sum(num_disaster_month)) %>%
mutate(disaster_rate = num_disaster_months / num_months) %>%
pivot_wider(id_cols = c(lat_box, lng_box, half_year), names_from = c(Event_factor, wet_string), values_from = c(disaster_rate), values_fill = 0) %>%
mutate(positive_wet_relative_risk = positive_wet_disasters / no_event_wet_disasters,
negative_wet_relative_risk = negative_wet_disasters / no_event_wet_disasters,
positive_dry_relative_risk = positive_dry_disasters / no_event_dry_disasters,
negative_dry_relative_risk = negative_dry_disasters / no_event_dry_disasters) %>%
select(lat_box, lng_box, half_year, positive_wet_relative_risk, negative_wet_relative_risk, positive_dry_relative_risk, negative_dry_relative_risk) %>%
pivot_longer(cols = c(positive_wet_relative_risk, negative_wet_relative_risk, positive_dry_relative_risk, negative_dry_relative_risk), names_to = 'risk', values_to = 'value') %>%
mutate(risk_factor = as_factor(risk), values_cleaned = if_else(is.infinite(value), 18, value)) %>%
mutate(relative_risk_cleaned = if_else(is.nan(values_cleaned), 1, values_cleaned)) %>%
mutate(relative_risk_cleaned_truncatedat2 = if_else((relative_risk_cleaned) > 2, 2, relative_risk_cleaned)) %>%
select(lat_box, lng_box, half_year, risk_factor, relative_risk_cleaned, relative_risk_cleaned_truncatedat2) %>%
ggplot() +
geom_sf(data = world_map) +
geom_tile(mapping = aes(x = lng_box, y = lat_box, fill = relative_risk_cleaned_truncatedat2, width = resy)) +
scale_fill_gradient2(midpoint = 1, limits = c(0, 2), low = 'cyan', high = 'red') +
facet_grid(rows = vars(risk_factor), cols = vars(half_year))+
ggtitle("Half year Relative risk plot using calculations of the form [{num_disasters_positive_wet / num_months_positive} / {num_disasters_no_event_wet / num_months_no_event}]")
`summarise()` has grouped output by 'lat_box', 'lng_box', 'Event_factor', 'wet_string', 'dis_no_factor'. You can override using the `.groups` argument.`summarise()` has grouped output by 'lat_box', 'lng_box', 'Event_factor', 'wet_string'. You can override using the `.groups` argument.

NA
Dry Disasters
resy <- 2.5
emdat_hydrological_enso %>%
filter(dry) %>%
mutate(lat_box = (as.integer(lat) %/% resy) * resy , lng_box = (as.integer(lng) %/% resy) * resy) %>%
group_by(`Dis No`, lat_box, lng_box) %>%
summarise(disaster_type = first(`Disaster Type`)) %>%
group_by(disaster_type, lat_box, lng_box) %>%
summarise(county = n()) %>%
filter(county > 0) %>%
ggplot() +
geom_sf(data = world_map) +
geom_tile(mapping = aes(x = lng_box, y = lat_box, fill = county, width = resy)) +
scale_fill_continuous(type="gradient", low = "white", high = "red") +
facet_grid(rows = vars(disaster_type))+
ggtitle("Dry disaster types around the world")
`summarise()` has grouped output by 'Dis No', 'lat_box'. You can override using the `.groups` argument.`summarise()` has grouped output by 'disaster_type', 'lat_box'. You can override using the `.groups` argument.

emdat_hydrological_enso %>%
filter(dry) %>%
filter(!is.na(Event)) %>%
mutate(lat_box = (as.integer(lat) %/% resy) * resy , lng_box = (as.integer(lng) %/% resy) * resy) %>%
group_by(`Dis No`, Event) %>%
summarise(disaster_type = first(`Disaster Type`)) %>%
ggplot() +
geom_bar(mapping = aes(x = disaster_type, stat = "count")) +
facet_grid(~Event)
`summarise()` has grouped output by 'Dis No'. You can override using the `.groups` argument.Warning: Ignoring unknown aesthetics: stat

emdat_hydrological_enso %>%
filter(dry) %>%
filter(!is.na(Event)) %>%
mutate(lat_box = (as.integer(lat) %/% resy) * resy , lng_box = (as.integer(lng) %/% resy) * resy) %>%
group_by(`Dis No`, Event) %>%
summarise(disaster_type = first(`Disaster Type`)) %>%
ggplot() +
geom_bar(mapping = aes(x = Event, stat = "count")) +
facet_grid(~disaster_type)
`summarise()` has grouped output by 'Dis No'. You can override using the `.groups` argument.Warning: Ignoring unknown aesthetics: stat

Looking at ENSO Value


Create Data as NetCDF
resy <- 2.5
df_to_be_spatialized <- emdat_hydrological_enso %>%
mutate(lat_box = (as.integer(lat) %/% resy) * resy , lng_box = (as.integer(lng) %/% resy) * resy) %>%
mutate(month_number = (end_year * 12) + end_month) %>%
group_by(lat_box, lng_box, month_number, `Dis No`, `Disaster Type`) %>%
summarize(enso_value = mean(enso_Value), Event = first(Event), num_months_disaster = mean(num_months_disaster)) %>%
group_by(lat_box, lng_box, month_number, `Disaster Type`) %>%
summarize(enso_value = mean(enso_value), Event = first(Event), num_disaster_months = sum(num_months_disaster)) %>%
filter(!is.na(lat_box))
`summarise()` has grouped output by 'lat_box', 'lng_box', 'month_number', 'Dis No'. You can override using the `.groups` argument.`summarise()` has grouped output by 'lat_box', 'lng_box', 'month_number'. You can override using the `.groups` argument.
LS0tCnRpdGxlOiAiRU5TTyBhbmFseXNpcyBuZXciCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUpCmBgYAoKIyMgUGFja2FnZXMKCmBgYHtyfQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShzZikKbGlicmFyeShoZXJlKQpsaWJyYXJ5KHdlZWQpCmxpYnJhcnkocm5hdHVyYWxlYXJ0aCkKbGlicmFyeShybmF0dXJhbGVhcnRoZGF0YSkKYGBgCgojIyBMb2FkaW5nIEluIHRoZSBEYXRhCgpgYGB7cn0KZW1kYXRfb2xkIDwtIHJlYWRfY3N2KCd+L0Rlc2t0b3AvcHJvamVjdHMvZW1kYXRfcHJvai9mdWxsX2VtZGF0X2dlb2NvZGVkX2ZpbmFsbHkuY3N2JykKZW1kYXRfbmV3IDwtIHJlYWRfY3N2KCd+L0Rlc2t0b3AvcHJvamVjdHMvZW1kYXRfcHJvai9kYXRhL2dlb2NvZGVkXzIxXzIzX2VtZGF0LmNzdicpCgplbWRhdCA8LSBiaW5kX3Jvd3MoZW1kYXRfb2xkLCBlbWRhdF9uZXcpCmBgYAojIEhvdyBtYW55IGRpc2FzdGVycyB3ZXJlIGxvY2F0ZWQ/CgpgYGB7cn0KZW1kYXQgJT4lCiAgcGVyY2VudF9sb2NhdGVkX2Rpc2FzdGVycyhwbG90X3Jlc3VsdD1GQUxTRSkKYGBgCgojIEhvdyBtYW55IGxvY2F0aW9ucyB3ZXJlIGxvY2F0ZWQ/CgpgYGB7cn0KZW1kYXQgJT4lCiAgcGVyY2VudF9sb2NhdGVkX2xvY2F0aW9ucyhwbG90X3Jlc3VsdD1GQUxTRSkKYGBgCiMgQWxsIHR5cGVzIG9mIGRpc2FzdGVycwoKYGBge3J9CmVtZGF0ICU+JQogIGdyb3VwX2J5KGBEaXNhc3RlciBUeXBlYCkgJT4lCiAgY291bnQoKQpgYGAKCiMgUmVzdHJpY3QgdG8gZHJ5IGFuZCB3ZXQgaHlkcm9sb2dpY2FsIGRpc2FzdGVycwoKYGBge3J9CmRyeV9saXN0IDwtIGMoIkRyb3VnaHQiLCAiV2lsZGZpcmUiKQp3ZXRfbGlzdCA8LSBjKCJGbG9vZCIsICJMYW5kc2xpZGUiLCAiU3Rvcm0iKQoKZW1kYXRfaHlkcm9sb2dpY2FsIDwtIGVtZGF0ICU+JQogIGZpbHRlcihgRGlzYXN0ZXIgVHlwZWAgJWluJSBjKGRyeV9saXN0LCB3ZXRfbGlzdCkpICU+JQogIG11dGF0ZShkcnkgPSAoYERpc2FzdGVyIFR5cGVgICVpbiUgZHJ5X2xpc3QpLCB3ZXQgPSAoYERpc2FzdGVyIFR5cGVgICVpbiUgd2V0X2xpc3QpKQpgYGAKCmBgYHtyfQplbWRhdF9oeWRyb2xvZ2ljYWwgJT4lCiAgZ3JvdXBfYnkoYERpc2FzdGVyIFR5cGVgKSAlPiUKICBjb3VudCgpCmBgYAoKIyBFTlNPIGRhdGEKCmBgYHtyfQplbnNvX2RhdGEgPC0gcmVhZF9jc3YoJ34vRGVza3RvcC9wcm9qZWN0cy9lbWRhdF9wcm9qL2RhdGEvZW5zb19kYXRhX2NvcHkyLmNzdicpCmVuc29fZGF0YSAlPiUKICBncm91cF9ieShFdmVudCkgJT4lCiAgY291bnQoKQpgYGAKCmBgYHtyfQoKZW1kYXRfaHlkcm9sb2dpY2FsMiA8LSBlbWRhdF9oeWRyb2xvZ2ljYWwgJT4lCiAgZmlsdGVyKCFpcy5uYShgU3RhcnQgTW9udGhgKSkgJT4lCiAgbXV0YXRlKHN0YXJ0X3llYXIgPSBpZl9lbHNlKGlzLm5hKGBTdGFydCBZZWFyYCksIFllYXIsIGBTdGFydCBZZWFyYCkpICU+JQogIG11dGF0ZShlbmRfeWVhciA9IGlmX2Vsc2UoaXMubmEoYEVuZCBZZWFyYCksIHN0YXJ0X3llYXIsIGBFbmQgWWVhcmApKSAlPiUKICBtdXRhdGUoZW5kX21vbnRoID0gaWZfZWxzZShpcy5uYShgRW5kIE1vbnRoYCksIGBTdGFydCBNb250aGAsIGBFbmQgTW9udGhgKSkgJT4lCiAgbXV0YXRlKG51bV9tb250aHNfZGlzYXN0ZXIgPSAoZW5kX21vbnRoIC0gYFN0YXJ0IE1vbnRoYCArIDEpICsgMTIgKiAoZW5kX3llYXIgLSBzdGFydF95ZWFyKSkgJT4lCiAgZmlsdGVyKG51bV9tb250aHNfZGlzYXN0ZXIgPiAwKQoKZW1kYXRfaHlkcm9sb2dpY2FsX2Vuc28gPC0gZW1kYXRfaHlkcm9sb2dpY2FsICU+JQogIGZ1bGxfam9pbihlbnNvX2RhdGEsIGJ5ID0gYygiWWVhciIgPSAiWWVhciIsICJTdGFydCBNb250aCIgPSAiTW9udGhOdW0iKSkgJT4lCiAgcmVuYW1lKCJlbnNvX1ZhbHVlIiA9ICJWYWx1ZSIpICU+JQogIGZpbHRlcighaXMubmEoYFN0YXJ0IE1vbnRoYCkpICU+JQogIG11dGF0ZShzdGFydF95ZWFyID0gaWZfZWxzZShpcy5uYShgU3RhcnQgWWVhcmApLCBZZWFyLCBgU3RhcnQgWWVhcmApKSAlPiUKICBtdXRhdGUoZW5kX3llYXIgPSBpZl9lbHNlKGlzLm5hKGBFbmQgWWVhcmApLCBzdGFydF95ZWFyLCBgRW5kIFllYXJgKSkgJT4lCiAgbXV0YXRlKGVuZF9tb250aCA9IGlmX2Vsc2UoaXMubmEoYEVuZCBNb250aGApLCBgU3RhcnQgTW9udGhgLCBgRW5kIE1vbnRoYCkpICU+JQogIG11dGF0ZShudW1fbW9udGhzX2Rpc2FzdGVyID0gKGVuZF9tb250aCAtIGBTdGFydCBNb250aGAgKyAxKSArIDEyICogKGVuZF95ZWFyIC0gc3RhcnRfeWVhcikpICU+JQogIGZpbHRlcihudW1fbW9udGhzX2Rpc2FzdGVyID4gMCkKCmVtZGF0X2h5ZHJvbG9naWNhbF9lbnNvICU+JQogIGdyb3VwX2J5KG51bV9tb250aHNfZGlzYXN0ZXIpICU+JQogIHN1bW1hcml6ZShjb3VudF9kaXNhc3RlcnMgPSBuX2Rpc3RpbmN0KGBEaXMgTm9gKSkKYGBgCgpgYGB7cn0KZW1kYXRfaHlkcm9sb2dpY2FsX2Vuc28gJT4lCiAgZmlsdGVyKCFpcy5uYShlbnNvX1ZhbHVlKSkgJT4lCiAgZmlsdGVyKCFpcy5uYSh3ZXQpKSAlPiUKICBtdXRhdGUoZW5zb19wb3NpdGl2ZSA9IChlbnNvX1ZhbHVlID4gMCkpICU+JQogIGdyb3VwX2J5KGBEaXMgTm9gKSAlPiUKICBzdW1tYXJpemUoZW5zb19wb3MgPSBhbnkoZW5zb19wb3NpdGl2ZSksZW5zb192YWwgPSBtZWFuKGVuc29fVmFsdWUpLCBpc193ZXQgPSBhbnkod2V0KSkgJT4lCiAgZ2dwbG90KG1hcHBpbmcgPSBhZXMoeCA9IGVuc29fdmFsLCBmaWxsID0gaXNfd2V0KSkgKwogICAgZ2VvbV9oaXN0b2dyYW0oc3RhdCA9ICJkZW5zaXR5IikgKwogICAgZmFjZXRfZ3JpZCh+aXNfd2V0KSArCiAgZ2d0aXRsZSgiQ291bnRzIG9mIERpc2FzdGVycyBjb21wYXJlZCB0byB2YWx1ZSBvZiBPTkkgd2l0aCB3ZXQgZGlzYXN0ZXJzIGluIEJsdWUgYW5kIERyeSBpbiBSZWQiKQpgYGAKYGBge3J9CmVtZGF0X2h5ZHJvbG9naWNhbF9lbnNvICU+JQogIGZpbHRlcighaXMubmEoZW5zb19WYWx1ZSkpICU+JQogIGZpbHRlcighaXMubmEod2V0KSkgJT4lCiAgI211dGF0ZShlbnNvX3Bvc2l0aXZlID0gKGVuc29fVmFsdWUgPiAwKSkgJT4lCiAgZ3JvdXBfYnkoYERpcyBOb2ApICU+JQogIHN1bW1hcml6ZShlbnNvX2V2ZW50ID0gZmlyc3QoRXZlbnQpLGVuc29fdmFsID0gbWVhbihlbnNvX1ZhbHVlKSwgaXNfd2V0ID0gYW55KHdldCksIGlzX2RyeSA9IGFueShkcnkpKSAlPiUKICBtdXRhdGUoaXNfd2V0X251bSA9IGFzLm51bWVyaWMoaXNfd2V0KSwgaXNfZHJ5X251bSA9IGFzLm51bWVyaWMoaXNfZHJ5KSkgJT4lCiAgZ3JvdXBfYnkoZW5zb19ldmVudCkgJT4lCiAgc3VtbWFyaXplKG51bV9kaXNhc3RlcnNfd2V0ID0gc3VtKGlzX3dldF9udW0pLCBudW1fZGlzYXN0ZXJzX2RyeSA9IHN1bShpc19kcnlfbnVtKSkKYGBgCmBgYHtyfQp3b3JsZF9tYXAgPC0gcm5hdHVyYWxlYXJ0aDo6bmVfY291bnRyaWVzKHNjYWxlID0gIm1lZGl1bSIsIHJldHVybmNsYXNzID0gInNmIikKCmVtZGF0X2h5ZHJvbG9naWNhbF9lbnNvICU+JQogIGZpbHRlcighaXMubmEoZW5zb19WYWx1ZSkpICU+JQogIGZpbHRlcighaXMubmEod2V0KSkgJT4lCiAgZmlsdGVyKCFpcy5uYShsYXQpKSAlPiUKICBtdXRhdGUoZW5zb19wb3NpdGl2ZSA9IChlbnNvX1ZhbHVlID4gMCkpICU+JQogIG11dGF0ZSh3ZXRfZmFjdG9yID0gYXNfZmFjdG9yKHdldCkpICU+JQogIG11dGF0ZSh3ZXRfc3RyaW5nID0gZmN0X3JlY29kZSh3ZXRfZmFjdG9yLCB3ZXRfZGlzYXN0ZXJzID0gIlRSVUUiLCBkcnlfZGlzYXN0ZXJzID0gIkZBTFNFIikpICU+JQogIHNlbGVjdChsbmcsIGxhdCwgZW5zb19WYWx1ZSwgd2V0X3N0cmluZykgJT4lCiAgI2hlYWQobiA9IDUwTCkgJT4lCiAgZ2dwbG90KCkgKwogIGdlb21fc2YoZGF0YSA9IHdvcmxkX21hcCkgKwogIGdlb21fdGlsZShtYXBwaW5nID0gYWVzKHggPSBsbmcsIHkgPSBsYXQsIGZpbGwgPSBlbnNvX1ZhbHVlLCB3aWR0aCA9IDIsIGhlaWdodCA9IDIpKSArCiAgc2NhbGVfZmlsbF9ncmFkaWVudDIobG93PSJibHVlIiwgbWlkID0gIndoaXRlIiwgaGlnaCA9ICJyZWQiKSArCiAgZmFjZXRfZ3JpZCh+d2V0X3N0cmluZykKICAKCmBgYApgYGB7cn0KCmVtZGF0X2h5ZHJvbG9naWNhbF9lbnNvICU+JQogIGZpbHRlcighaXMubmEoZW5zb19WYWx1ZSkpICU+JQogIGZpbHRlcighaXMubmEod2V0KSkgJT4lCiAgZmlsdGVyKCFpcy5uYShsYXQpKSAlPiUKICBtdXRhdGUod2V0X2ZhY3RvciA9IGFzX2ZhY3Rvcih3ZXQpKSAlPiUKICBtdXRhdGUoRXZlbnRfZmFjdG9yID0gZmN0X3JlY29kZShhc19mYWN0b3IoRXZlbnQpLCBub19ldmVudCA9ICJOIiwgbmVnYXRpdmUgPSAiLSIsIHBvc2l0aXZlID0gIisiKSkgJT4lCiAgbXV0YXRlKHdldF9zdHJpbmcgPSBmY3RfcmVjb2RlKHdldF9mYWN0b3IsIHdldF9kaXNhc3RlcnMgPSAiVFJVRSIsIGRyeV9kaXNhc3RlcnMgPSAiRkFMU0UiKSkgJT4lCiAgc2VsZWN0KGxuZywgbGF0LCBFdmVudF9mYWN0b3IsIHdldF9zdHJpbmcsIHdldCkgJT4lCiAgZ2dwbG90KCkgKwogIGdlb21fc2YoZGF0YSA9IHdvcmxkX21hcCkgKwogIGdlb21fdGlsZShtYXBwaW5nID0gYWVzKHggPSBsbmcsIHkgPSBsYXQsIHdpZHRoID0gMiwgaGVpZ2h0ID0gMiwgZmlsbCA9IDEsIGFscGhhID0gMC4wMDEpKSArCiAgZmFjZXRfZ3JpZChjb2xzID0gdmFycyh3ZXRfc3RyaW5nKSwgcm93cyA9IHZhcnMoRXZlbnRfZmFjdG9yKSkKCmBgYApgYGB7cn0KCmV2ZW50X251bV9tb250aHMgPC0gZW5zb19kYXRhICU+JQogIGdyb3VwX2J5KEV2ZW50KSAlPiUKICBzdW1tYXJpemUobnVtX21vbnRocyA9IG4oKSkKCmVtZGF0X2h5ZHJvbG9naWNhbF9lbnNvICU+JQogIGxlZnRfam9pbihldmVudF9udW1fbW9udGhzLCBieSA9IGMoIkV2ZW50IikpICU+JQogIGZpbHRlcighaXMubmEoZW5zb19WYWx1ZSkpICU+JQogIGZpbHRlcighaXMubmEod2V0KSkgJT4lCiAgZmlsdGVyKCFpcy5uYShsYXQpKSAlPiUKICBtdXRhdGUod2V0X2ZhY3RvciA9IGFzX2ZhY3Rvcih3ZXQpKSAlPiUKICBtdXRhdGUoRXZlbnRfZmFjdG9yID0gZmN0X3JlY29kZShhc19mYWN0b3IoRXZlbnQpLCBub19ldmVudCA9ICJOIiwgbmVnYXRpdmUgPSAiLSIsIHBvc2l0aXZlID0gIisiKSkgJT4lCiAgbXV0YXRlKHdldF9zdHJpbmcgPSBmY3RfcmVjb2RlKHdldF9mYWN0b3IsIHdldF9kaXNhc3RlcnMgPSAiVFJVRSIsIGRyeV9kaXNhc3RlcnMgPSAiRkFMU0UiKSkgJT4lCiAgc2VsZWN0KGxuZywgbGF0LCBFdmVudF9mYWN0b3IsIHdldF9zdHJpbmcsIG51bV9tb250aHMsIG51bV9tb250aHNfZGlzYXN0ZXIpICU+JQogIGFkZF9yb3cobG5nID0gMSwgbGF0ID0gMSwgRXZlbnRfZmFjdG9yID0gJ25vX2V2ZW50Jywgd2V0X3N0cmluZyA9ICdkcnlfZGlzYXN0ZXJzJywgbnVtX21vbnRocyA9IDEpICU+JQogIGdncGxvdCgpICsKICBnZW9tX3NmKGRhdGEgPSB3b3JsZF9tYXApICsKICBnZW9tX3RpbGUobWFwcGluZyA9IGFlcyh4ID0gbG5nLCB5ID0gbGF0LCB3aWR0aCA9IDIsIGhlaWdodCA9IDIsIGFscGhhID0gbnVtX21vbnRoc19kaXNhc3Rlci9udW1fbW9udGhzLCBmaWxsID0gJ3JlZCcpKSArCiAgZmFjZXRfZ3JpZChjb2xzID0gdmFycyh3ZXRfc3RyaW5nKSwgcm93cyA9IHZhcnMoRXZlbnRfZmFjdG9yKSkgKwogIGdndGl0bGUoIlNhbWUgcGxvdCBhcyBhYm92ZSBidXQgc2NhbGVkIGJ5IG51bSBtb250aHMiKQoKYGBgCgpgYGB7cn0KZW1kYXRfaHlkcm9sb2dpY2FsX2Vuc28gJT4lCiAgbGVmdF9qb2luKGV2ZW50X251bV9tb250aHMsIGJ5ID0gYygiRXZlbnQiKSkgJT4lCiAgZmlsdGVyKCFpcy5uYShlbnNvX1ZhbHVlKSkgJT4lCiAgZmlsdGVyKCFpcy5uYSh3ZXQpKSAlPiUKICBmaWx0ZXIoIWlzLm5hKGxhdCkpICU+JQogIG11dGF0ZSh3ZXRfZmFjdG9yID0gYXNfZmFjdG9yKHdldCkpICU+JQogIG11dGF0ZShFdmVudF9mYWN0b3IgPSBmY3RfcmVjb2RlKGFzX2ZhY3RvcihFdmVudCksIG5vX2V2ZW50ID0gIk4iLCBuZWdhdGl2ZSA9ICItIiwgcG9zaXRpdmUgPSAiKyIpKSAlPiUKICBtdXRhdGUod2V0X3N0cmluZyA9IGZjdF9yZWNvZGUod2V0X2ZhY3Rvciwgd2V0X2Rpc2FzdGVycyA9ICJUUlVFIiwgZHJ5X2Rpc2FzdGVycyA9ICJGQUxTRSIpKSAlPiUKICBzZWxlY3QobG5nLCBsYXQsIEV2ZW50X2ZhY3Rvciwgd2V0X3N0cmluZywgbnVtX21vbnRocykgJT4lCiAgZ2dwbG90KCkgKwogIGdlb21fc2YoZGF0YSA9IHdvcmxkX21hcCkgKwogIHN0YXRfYmluXzJkKG1hcHBpbmcgPSBhZXMoeCA9IGxuZywgeSA9IGxhdCksIGJpbndpZHRoID0gYygyLDIpKSArCiAgc2NhbGVfZmlsbF9ncmFkaWVudCh0cmFucyA9ICdsb2cnLCBsb3cgPSAnd2hpdGUnLCBoaWdoID0gJ3JlZCcpICsgCiAgZmFjZXRfZ3JpZChjb2xzID0gdmFycyh3ZXRfc3RyaW5nKSwgcm93cyA9IHZhcnMoRXZlbnRfZmFjdG9yKSkgKwogIGdndGl0bGUoIjJEIEhpc3RvZ3JhbSBDb3VudHMgIikKCmBgYApgYGB7cn0KCmVtZGF0X2h5ZHJvbG9naWNhbF9lbnNvICU+JQogIGxlZnRfam9pbihldmVudF9udW1fbW9udGhzLCBieSA9IGMoIkV2ZW50IikpICU+JQogIGZpbHRlcighaXMubmEoZW5zb19WYWx1ZSkpICU+JQogIGZpbHRlcighaXMubmEod2V0KSkgJT4lCiAgZmlsdGVyKCFpcy5uYShsYXQpKSAlPiUKICBtdXRhdGUod2V0X2ZhY3RvciA9IGFzX2ZhY3Rvcih3ZXQpKSAlPiUKICBtdXRhdGUoRXZlbnRfZmFjdG9yID0gZmN0X3JlY29kZShhc19mYWN0b3IoRXZlbnQpLCBub19ldmVudCA9ICJOIiwgbmVnYXRpdmUgPSAiLSIsIHBvc2l0aXZlID0gIisiKSkgJT4lCiAgbXV0YXRlKHdldF9zdHJpbmcgPSBmY3RfcmVjb2RlKHdldF9mYWN0b3IsIHdldF9kaXNhc3RlcnMgPSAiVFJVRSIsIGRyeV9kaXNhc3RlcnMgPSAiRkFMU0UiKSkgJT4lCiAgc2VsZWN0KGxuZywgbGF0LCBFdmVudF9mYWN0b3IsIHdldF9zdHJpbmcsIG51bV9tb250aHMpICU+JQogIGdncGxvdCgpICsKICBnZW9tX3NmKGRhdGEgPSB3b3JsZF9tYXApICsKICBzdGF0X2Jpbl8yZChtYXBwaW5nID0gYWVzKHggPSBsbmcsIHkgPSBsYXQsIGZpbGwgPSAuLmRlbnNpdHkuLiksIGJpbndpZHRoID0gYygyLDIpKSArCiAgc2NhbGVfZmlsbF9ncmFkaWVudCh0cmFucyA9ICdsb2cnLCBsb3cgPSAnd2hpdGUnLCBoaWdoID0gJ3JlZCcpICsgCiAgZmFjZXRfZ3JpZChjb2xzID0gdmFycyh3ZXRfc3RyaW5nKSwgcm93cyA9IHZhcnMoRXZlbnRfZmFjdG9yKSkgKwogIGdndGl0bGUoIjJEIEhpc3RvZ3JhbSBEZW5zaXR5IikKCmBgYAoKYGBge3J9CgplbWRhdF9oeWRyb2xvZ2ljYWxfZW5zbyAlPiUKICBsZWZ0X2pvaW4oZXZlbnRfbnVtX21vbnRocywgYnkgPSBjKCJFdmVudCIpKSAlPiUKICBmaWx0ZXIoIWlzLm5hKGVuc29fVmFsdWUpKSAlPiUKICBmaWx0ZXIoIWlzLm5hKHdldCkpICU+JQogIGZpbHRlcighaXMubmEobGF0KSkgJT4lCiAgbXV0YXRlKHdldF9mYWN0b3IgPSBhc19mYWN0b3Iod2V0KSkgJT4lCiAgbXV0YXRlKEV2ZW50X2ZhY3RvciA9IGZjdF9yZWNvZGUoYXNfZmFjdG9yKEV2ZW50KSwgbm9fZXZlbnQgPSAiTiIsIG5lZ2F0aXZlID0gIi0iLCBwb3NpdGl2ZSA9ICIrIikpICU+JQogIG11dGF0ZSh3ZXRfc3RyaW5nID0gZmN0X3JlY29kZSh3ZXRfZmFjdG9yLCB3ZXRfZGlzYXN0ZXJzID0gIlRSVUUiLCBkcnlfZGlzYXN0ZXJzID0gIkZBTFNFIikpICU+JQogIHNlbGVjdChsbmcsIGxhdCwgRXZlbnRfZmFjdG9yLCB3ZXRfc3RyaW5nLCBudW1fbW9udGhzLCBudW1fbW9udGhzX2Rpc2FzdGVyKSAlPiUKICBnZ3Bsb3QoKSArCiAgZ2VvbV9zZihkYXRhID0gd29ybGRfbWFwKSArCiAgc3RhdF9iaW5fMmQobWFwcGluZyA9IGFlcyh4ID0gbG5nLCB5ID0gbGF0LCB3ZWlnaHQgPSBudW1fbW9udGhzX2Rpc2FzdGVyL251bV9tb250aHMpLCBiaW53aWR0aCA9IGMoMiwyKSkgKwogIHNjYWxlX2ZpbGxfZ3JhZGllbnQodHJhbnMgPSAnbG9nJywgbG93ID0gJ3doaXRlJywgaGlnaCA9ICdyZWQnKSArIAogIGZhY2V0X2dyaWQoY29scyA9IHZhcnMod2V0X3N0cmluZyksIHJvd3MgPSB2YXJzKEV2ZW50X2ZhY3RvcikpICsKICBnZ3RpdGxlKCIyRCBIaXN0b2dyYW0gSW52ZXJzZSBXZWlnaHRlZCBieSBOdW0gTW9udGhzIikKCmBgYApgYGB7cn0KIyMgY2FsY3VsYXRlIHJlbGF0aXZlIHJpc2sgd2l0aGluIGVhY2ggYm94CiMjIyBjcmVhdGUgYm94ZXMgYWNjIHRvIHJlc3kgWCByZXN5CgpyZXN5IDwtIDIuNQoKZW1kYXRfaHlkcm9sb2dpY2FsX2Vuc28gJT4lCiAgbGVmdF9qb2luKGV2ZW50X251bV9tb250aHMsIGJ5ID0gYygiRXZlbnQiKSkgJT4lCiAgZmlsdGVyKCFpcy5uYShlbnNvX1ZhbHVlKSkgJT4lCiAgZmlsdGVyKCFpcy5uYSh3ZXQpKSAlPiUKICBmaWx0ZXIoIWlzLm5hKGxhdCkpICU+JQogIG11dGF0ZSh3ZXRfZmFjdG9yID0gYXNfZmFjdG9yKHdldCkpICU+JQogIG11dGF0ZShFdmVudF9mYWN0b3IgPSBmY3RfcmVjb2RlKGFzX2ZhY3RvcihFdmVudCksIG5vX2V2ZW50ID0gIk4iLCBuZWdhdGl2ZSA9ICItIiwgcG9zaXRpdmUgPSAiKyIpKSAlPiUKICBtdXRhdGUod2V0X3N0cmluZyA9IGZjdF9yZWNvZGUod2V0X2ZhY3Rvciwgd2V0X2Rpc2FzdGVycyA9ICJUUlVFIiwgZHJ5X2Rpc2FzdGVycyA9ICJGQUxTRSIpKSAlPiUKICBtdXRhdGUobGF0X2JveCA9IChhcy5pbnRlZ2VyKGxhdCkgJS8lIHJlc3kpICogcmVzeSAsIGxuZ19ib3ggPSAoYXMuaW50ZWdlcihsbmcpICUvJSByZXN5KSAqIHJlc3kpICU+JQogIG11dGF0ZShkaXNfbm9fZmFjdG9yID0gYXNfZmFjdG9yKGBEaXMgTm9gKSkgJT4lCiAgZ3JvdXBfYnkobGF0X2JveCwgbG5nX2JveCwgRXZlbnRfZmFjdG9yLCB3ZXRfc3RyaW5nLCBkaXNfbm9fZmFjdG9yKSAlPiUKICBzdW1tYXJpemUobnVtX21vbnRocyA9IGZpcnN0KG51bV9tb250aHMpLCBudW1fZGlzYXN0ZXJfbW9udGggPSBtZWFuKG51bV9tb250aHNfZGlzYXN0ZXIpKSAlPiUKICBncm91cF9ieShsYXRfYm94LCBsbmdfYm94LCBFdmVudF9mYWN0b3IsIHdldF9zdHJpbmcpICU+JQogIHN1bW1hcml6ZShudW1fbW9udGhzID0gZmlyc3QobnVtX21vbnRocyksIG51bV9kaXNhc3Rlcl9tb250aHMgPSBzdW0obnVtX2Rpc2FzdGVyX21vbnRoKSkgJT4lCiAgbXV0YXRlKGRpc2FzdGVyX3JhdGUgPSBudW1fZGlzYXN0ZXJfbW9udGhzIC8gbnVtX21vbnRocykgJT4lCiAgcGl2b3Rfd2lkZXIoaWRfY29scyA9IGMobGF0X2JveCwgbG5nX2JveCksIG5hbWVzX2Zyb20gPSBjKEV2ZW50X2ZhY3Rvciwgd2V0X3N0cmluZyksIHZhbHVlc19mcm9tID0gYyhkaXNhc3Rlcl9yYXRlKSwgdmFsdWVzX2ZpbGwgPSAwKSAlPiUKICBtdXRhdGUocG9zaXRpdmVfd2V0X3JlbGF0aXZlX3Jpc2sgPSBwb3NpdGl2ZV93ZXRfZGlzYXN0ZXJzIC8gbm9fZXZlbnRfd2V0X2Rpc2FzdGVycywgCiAgICAgICAgIG5lZ2F0aXZlX3dldF9yZWxhdGl2ZV9yaXNrID0gbmVnYXRpdmVfd2V0X2Rpc2FzdGVycyAvIG5vX2V2ZW50X3dldF9kaXNhc3RlcnMsIAogICAgICAgICBwb3NpdGl2ZV9kcnlfcmVsYXRpdmVfcmlzayA9ICBwb3NpdGl2ZV9kcnlfZGlzYXN0ZXJzIC8gbm9fZXZlbnRfZHJ5X2Rpc2FzdGVycywKICAgICAgICAgbmVnYXRpdmVfZHJ5X3JlbGF0aXZlX3Jpc2sgPSBuZWdhdGl2ZV9kcnlfZGlzYXN0ZXJzIC8gbm9fZXZlbnRfZHJ5X2Rpc2FzdGVycykgJT4lCiAgc2VsZWN0KGxhdF9ib3gsIGxuZ19ib3gsIHBvc2l0aXZlX3dldF9yZWxhdGl2ZV9yaXNrLCBuZWdhdGl2ZV93ZXRfcmVsYXRpdmVfcmlzaywgcG9zaXRpdmVfZHJ5X3JlbGF0aXZlX3Jpc2ssIG5lZ2F0aXZlX2RyeV9yZWxhdGl2ZV9yaXNrKSAlPiUKICBwaXZvdF9sb25nZXIoY29scyA9IGMocG9zaXRpdmVfd2V0X3JlbGF0aXZlX3Jpc2ssIG5lZ2F0aXZlX3dldF9yZWxhdGl2ZV9yaXNrLCBwb3NpdGl2ZV9kcnlfcmVsYXRpdmVfcmlzaywgbmVnYXRpdmVfZHJ5X3JlbGF0aXZlX3Jpc2spLCBuYW1lc190byA9ICdyaXNrJywgdmFsdWVzX3RvID0gJ3ZhbHVlJykgJT4lCiAgbXV0YXRlKHJpc2tfZmFjdG9yID0gYXNfZmFjdG9yKHJpc2spLCB2YWx1ZXNfY2xlYW5lZCA9IGlmX2Vsc2UoaXMuaW5maW5pdGUodmFsdWUpLCAxOCwgdmFsdWUpKSAlPiUKICBtdXRhdGUocmVsYXRpdmVfcmlza19jbGVhbmVkID0gaWZfZWxzZShpcy5uYW4odmFsdWVzX2NsZWFuZWQpLCAxLCB2YWx1ZXNfY2xlYW5lZCkpICU+JQogIG11dGF0ZShyZWxhdGl2ZV9yaXNrX2NsZWFuZWQyID0gaWZfZWxzZSgocmVsYXRpdmVfcmlza19jbGVhbmVkKSA+IDIsIDIsIHJlbGF0aXZlX3Jpc2tfY2xlYW5lZCkpICU+JQogIGdncGxvdCgpICsKICBnZW9tX3NmKGRhdGEgPSB3b3JsZF9tYXApICsKICBnZW9tX3RpbGUobWFwcGluZyA9IGFlcyh4ID0gbG5nX2JveCwgeSA9IGxhdF9ib3gsIGZpbGwgPSByZWxhdGl2ZV9yaXNrX2NsZWFuZWQyLCB3aWR0aCA9IHJlc3kpKSArCiAgc2NhbGVfZmlsbF9ncmFkaWVudDIobWlkcG9pbnQgPSAxLCBsaW1pdHMgPSBjKDAsIDIpLCBsb3cgPSAnY3lhbicsIGhpZ2ggPSAncmVkJykgKwogIGZhY2V0X2dyaWQocm93cyA9IHZhcnMocmlza19mYWN0b3IpKSsKICBnZ3RpdGxlKCJSZWxhdGl2ZSByaXNrIHBsb3QgdXNpbmcgY2FsY3VsYXRpb25zIG9mIHRoZSBmb3JtIFt7bnVtX2Rpc2FzdGVyc19wb3NpdGl2ZV93ZXQgLyBudW1fbW9udGhzX3Bvc2l0aXZlfSAvIHtudW1fZGlzYXN0ZXJzX25vX2V2ZW50X3dldCAvIG51bV9tb250aHNfbm9fZXZlbnR9XSIpCiAgCiAgCgpgYGAKCmBgYHtyfQojIyBjYWxjdWxhdGUgcGVyY2VudCBvZiB0b3RhbCBkaXNhc3RlcnMgd2l0aGluIGVhY2ggYm94CiMjIyBjcmVhdGUgYm94ZXMgMngyCgpyZXN5IDwtIDIuNQoKZW1kYXRfaHlkcm9sb2dpY2FsX2Vuc28gJT4lCiAgbGVmdF9qb2luKGV2ZW50X251bV9tb250aHMsIGJ5ID0gYygiRXZlbnQiKSkgJT4lCiAgZmlsdGVyKCFpcy5uYShlbnNvX1ZhbHVlKSkgJT4lCiAgZmlsdGVyKCFpcy5uYSh3ZXQpKSAlPiUKICBmaWx0ZXIoIWlzLm5hKGxhdCkpICU+JQogIG11dGF0ZSh3ZXRfZmFjdG9yID0gYXNfZmFjdG9yKHdldCkpICU+JQogIG11dGF0ZShFdmVudF9mYWN0b3IgPSBmY3RfcmVjb2RlKGFzX2ZhY3RvcihFdmVudCksIG5vX2V2ZW50ID0gIk4iLCBuZWdhdGl2ZSA9ICItIiwgcG9zaXRpdmUgPSAiKyIpKSAlPiUKICBtdXRhdGUod2V0X3N0cmluZyA9IGZjdF9yZWNvZGUod2V0X2ZhY3Rvciwgd2V0X2Rpc2FzdGVycyA9ICJUUlVFIiwgZHJ5X2Rpc2FzdGVycyA9ICJGQUxTRSIpKSAlPiUKICBtdXRhdGUobGF0X2JveCA9IChhcy5pbnRlZ2VyKGxhdCkgJS8lIHJlc3kpICogcmVzeSAsIGxuZ19ib3ggPSAoYXMuaW50ZWdlcihsbmcpICUvJSByZXN5KSAqIHJlc3kpICU+JQogIG11dGF0ZShkaXNfbm9fZmFjdG9yID0gYXNfZmFjdG9yKGBEaXMgTm9gKSkgJT4lCiAgZ3JvdXBfYnkobGF0X2JveCwgbG5nX2JveCwgRXZlbnRfZmFjdG9yLCB3ZXRfc3RyaW5nLCBkaXNfbm9fZmFjdG9yKSAlPiUKICBzdW1tYXJpemUobnVtX21vbnRocyA9IGZpcnN0KG51bV9tb250aHMpLCBudW1fZGlzYXN0ZXJfbW9udGggPSBtZWFuKG51bV9tb250aHNfZGlzYXN0ZXIpKSAlPiUKICBncm91cF9ieShsYXRfYm94LCBsbmdfYm94LCBFdmVudF9mYWN0b3IsIHdldF9zdHJpbmcpICU+JQogIHN1bW1hcml6ZShudW1fbW9udGhzID0gZmlyc3QobnVtX21vbnRocyksIG51bV9kaXNhc3Rlcl9tb250aHMgPSBzdW0obnVtX2Rpc2FzdGVyX21vbnRoKSkgJT4lCiAgbXV0YXRlKGRpc2FzdGVyX3JhdGUgPSBudW1fZGlzYXN0ZXJfbW9udGhzIC8gbnVtX21vbnRocykgJT4lCiAgcGl2b3Rfd2lkZXIoaWRfY29scyA9IGMobGF0X2JveCwgbG5nX2JveCksIG5hbWVzX2Zyb20gPSBjKEV2ZW50X2ZhY3Rvciwgd2V0X3N0cmluZyksIHZhbHVlc19mcm9tID0gYyhkaXNhc3Rlcl9yYXRlKSwgdmFsdWVzX2ZpbGwgPSAwKSAlPiUKICBtdXRhdGUocG9zaXRpdmVfd2V0X3BlcmNlbnQgPSBwb3NpdGl2ZV93ZXRfZGlzYXN0ZXJzIC8gKG5vX2V2ZW50X3dldF9kaXNhc3RlcnMgKyBwb3NpdGl2ZV93ZXRfZGlzYXN0ZXJzICsgbmVnYXRpdmVfd2V0X2Rpc2FzdGVycykgLCAKICAgICAgICAgbmVnYXRpdmVfd2V0X3BlcmNlbnQgPSBuZWdhdGl2ZV93ZXRfZGlzYXN0ZXJzIC8gKG5vX2V2ZW50X3dldF9kaXNhc3RlcnMgKyBwb3NpdGl2ZV93ZXRfZGlzYXN0ZXJzICsgbmVnYXRpdmVfd2V0X2Rpc2FzdGVycyksIAogICAgICAgICBwb3NpdGl2ZV9kcnlfcGVyY2VudCA9ICBwb3NpdGl2ZV9kcnlfZGlzYXN0ZXJzIC8gKG5vX2V2ZW50X2RyeV9kaXNhc3RlcnMgKyBwb3NpdGl2ZV9kcnlfZGlzYXN0ZXJzICsgbmVnYXRpdmVfZHJ5X2Rpc2FzdGVycyksCiAgICAgICAgIG5lZ2F0aXZlX2RyeV9wZXJjZW50ID0gIG5lZ2F0aXZlX2RyeV9kaXNhc3RlcnMgLyAobm9fZXZlbnRfZHJ5X2Rpc2FzdGVycyArIHBvc2l0aXZlX2RyeV9kaXNhc3RlcnMgKyBuZWdhdGl2ZV9kcnlfZGlzYXN0ZXJzKQogICAgICAgICApICU+JQogIHNlbGVjdChsYXRfYm94LCBsbmdfYm94LCBwb3NpdGl2ZV93ZXRfcGVyY2VudCwgbmVnYXRpdmVfd2V0X3BlcmNlbnQsIHBvc2l0aXZlX2RyeV9wZXJjZW50LCBuZWdhdGl2ZV9kcnlfcGVyY2VudCkgJT4lCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSBjKHBvc2l0aXZlX3dldF9wZXJjZW50LCBuZWdhdGl2ZV93ZXRfcGVyY2VudCwgcG9zaXRpdmVfZHJ5X3BlcmNlbnQsIG5lZ2F0aXZlX2RyeV9wZXJjZW50KSwgbmFtZXNfdG8gPSAndHlwZXknLCB2YWx1ZXNfdG8gPSAndmFsdWUnKSAlPiUKICBtdXRhdGUodHlwZV9mYWN0b3IgPSBhc19mYWN0b3IodHlwZXkpLCB2YWx1ZXMgPSBpZl9lbHNlKGlzLm5hbih2YWx1ZSksIDAsIHZhbHVlKSkgJT4lCiAgZ2dwbG90KCkgKwogIGdlb21fc2YoZGF0YSA9IHdvcmxkX21hcCkgKwogIGdlb21fdGlsZShtYXBwaW5nID0gYWVzKHggPSBsbmdfYm94LCB5ID0gbGF0X2JveCwgZmlsbCA9IHZhbHVlcywgd2lkdGggPSByZXN5KSkgKwogIHNjYWxlX2ZpbGxfZ3JhZGllbnQobG93ID0gJ3doaXRlJywgaGlnaCA9ICdyZWQnKSArCiAgZmFjZXRfZ3JpZChyb3dzID0gdmFycyh0eXBlX2ZhY3RvcikpKwogIGdndGl0bGUoIkRpc2FzdGVyIFBlcmNlbnQgcGxvdCB1c2luZyBjYWxjdWxhdGlvbnMgb2YgdGhlIGZvcm0gW3Bvc2l0aXZlX3dldCAvIGFsbF93ZXRdIikKICAKCmBgYAoKCmBgYHtyfQojIFNQTElUIFlFQVIgSU5UTyAyCiMgQXByIHRvIFNlcAojIE9jdCB0byBNYXIKIyMgY2FsY3VsYXRlIHJlbGF0aXZlIHJpc2sgd2l0aGluIGVhY2ggYm94CiMjIyBjcmVhdGUgYm94ZXMgYWNjIHRvIHJlc3kgWCByZXN5CgpyZXN5IDwtIDIuNQoKZXZlbnRfaGFsZl9udW1fbW9udGhzIDwtIGVuc29fZGF0YSAlPiUKICBtdXRhdGUoc3ByaW5nX3N1bW1lcnkgPSBhc19mYWN0b3IoKE1vbnRoTnVtID49IDQpICYgKE1vbnRoTnVtIDw9IDkpKSkgJT4lCiAgbXV0YXRlKGhhbGZfeWVhciA9IGZjdF9yZWNvZGUoc3ByaW5nX3N1bW1lcnksIHNwcmluZ19zdW1tZXIgPSAiVFJVRSIsIGZhbGxfd2ludGVyID0gIkZBTFNFIikpICU+JQogIGdyb3VwX2J5KEV2ZW50LCBoYWxmX3llYXIpICU+JQogIHN1bW1hcml6ZShudW1fbW9udGhzID0gbigpKQoKZW1kYXRfaHlkcm9sb2dpY2FsX2Vuc28gJT4lCiAgbXV0YXRlKHNwcmluZ19zdW1tZXJ5ID0gYXNfZmFjdG9yKChlbmRfbW9udGggPj0gNCkgJiAoZW5kX21vbnRoIDw9IDkpKSkgJT4lCiAgbXV0YXRlKGhhbGZfeWVhciA9IGZjdF9yZWNvZGUoc3ByaW5nX3N1bW1lcnksIHNwcmluZ19zdW1tZXIgPSAiVFJVRSIsIGZhbGxfd2ludGVyID0gIkZBTFNFIikpICU+JQogIGxlZnRfam9pbihldmVudF9oYWxmX251bV9tb250aHMsIGJ5ID0gYygiRXZlbnQiLCAiaGFsZl95ZWFyIikpICU+JQogIGZpbHRlcighaXMubmEoZW5zb19WYWx1ZSkpICU+JQogIGZpbHRlcighaXMubmEod2V0KSkgJT4lCiAgZmlsdGVyKCFpcy5uYShsYXQpKSAlPiUKICBtdXRhdGUod2V0X2ZhY3RvciA9IGFzX2ZhY3Rvcih3ZXQpKSAlPiUKICBtdXRhdGUoRXZlbnRfZmFjdG9yID0gZmN0X3JlY29kZShhc19mYWN0b3IoRXZlbnQpLCBub19ldmVudCA9ICJOIiwgbmVnYXRpdmUgPSAiLSIsIHBvc2l0aXZlID0gIisiKSkgJT4lCiAgbXV0YXRlKHdldF9zdHJpbmcgPSBmY3RfcmVjb2RlKHdldF9mYWN0b3IsIHdldF9kaXNhc3RlcnMgPSAiVFJVRSIsIGRyeV9kaXNhc3RlcnMgPSAiRkFMU0UiKSkgJT4lCiAgbXV0YXRlKGxhdF9ib3ggPSAoYXMuaW50ZWdlcihsYXQpICUvJSByZXN5KSAqIHJlc3kgLCBsbmdfYm94ID0gKGFzLmludGVnZXIobG5nKSAlLyUgcmVzeSkgKiByZXN5KSAlPiUKICBtdXRhdGUoZGlzX25vX2ZhY3RvciA9IGFzX2ZhY3RvcihgRGlzIE5vYCkpICU+JQogIGdyb3VwX2J5KGxhdF9ib3gsIGxuZ19ib3gsIEV2ZW50X2ZhY3Rvciwgd2V0X3N0cmluZywgZGlzX25vX2ZhY3RvciwgaGFsZl95ZWFyKSAlPiUKICBzdW1tYXJpemUobnVtX21vbnRocyA9IGZpcnN0KG51bV9tb250aHMpLCBudW1fZGlzYXN0ZXJfbW9udGggPSBtZWFuKG51bV9tb250aHNfZGlzYXN0ZXIpKSAlPiUKICBncm91cF9ieShsYXRfYm94LCBsbmdfYm94LCBFdmVudF9mYWN0b3IsIHdldF9zdHJpbmcsIGhhbGZfeWVhcikgJT4lCiAgc3VtbWFyaXplKG51bV9tb250aHMgPSBmaXJzdChudW1fbW9udGhzKSwgbnVtX2Rpc2FzdGVyX21vbnRocyA9IHN1bShudW1fZGlzYXN0ZXJfbW9udGgpKSAlPiUKICBtdXRhdGUoZGlzYXN0ZXJfcmF0ZSA9IG51bV9kaXNhc3Rlcl9tb250aHMgLyBudW1fbW9udGhzKSAlPiUKICBwaXZvdF93aWRlcihpZF9jb2xzID0gYyhsYXRfYm94LCBsbmdfYm94LCBoYWxmX3llYXIpLCBuYW1lc19mcm9tID0gYyhFdmVudF9mYWN0b3IsIHdldF9zdHJpbmcpLCB2YWx1ZXNfZnJvbSA9IGMoZGlzYXN0ZXJfcmF0ZSksIHZhbHVlc19maWxsID0gMCkgJT4lCiAgbXV0YXRlKHBvc2l0aXZlX3dldF9yZWxhdGl2ZV9yaXNrID0gcG9zaXRpdmVfd2V0X2Rpc2FzdGVycyAvIG5vX2V2ZW50X3dldF9kaXNhc3RlcnMsIAogICAgICAgICBuZWdhdGl2ZV93ZXRfcmVsYXRpdmVfcmlzayA9IG5lZ2F0aXZlX3dldF9kaXNhc3RlcnMgLyBub19ldmVudF93ZXRfZGlzYXN0ZXJzLCAKICAgICAgICAgcG9zaXRpdmVfZHJ5X3JlbGF0aXZlX3Jpc2sgPSAgcG9zaXRpdmVfZHJ5X2Rpc2FzdGVycyAvIG5vX2V2ZW50X2RyeV9kaXNhc3RlcnMsCiAgICAgICAgIG5lZ2F0aXZlX2RyeV9yZWxhdGl2ZV9yaXNrID0gbmVnYXRpdmVfZHJ5X2Rpc2FzdGVycyAvIG5vX2V2ZW50X2RyeV9kaXNhc3RlcnMpICU+JQogIHNlbGVjdChsYXRfYm94LCBsbmdfYm94LCBoYWxmX3llYXIsIHBvc2l0aXZlX3dldF9yZWxhdGl2ZV9yaXNrLCBuZWdhdGl2ZV93ZXRfcmVsYXRpdmVfcmlzaywgcG9zaXRpdmVfZHJ5X3JlbGF0aXZlX3Jpc2ssIG5lZ2F0aXZlX2RyeV9yZWxhdGl2ZV9yaXNrKSAlPiUKICBwaXZvdF9sb25nZXIoY29scyA9IGMocG9zaXRpdmVfd2V0X3JlbGF0aXZlX3Jpc2ssIG5lZ2F0aXZlX3dldF9yZWxhdGl2ZV9yaXNrLCBwb3NpdGl2ZV9kcnlfcmVsYXRpdmVfcmlzaywgbmVnYXRpdmVfZHJ5X3JlbGF0aXZlX3Jpc2spLCBuYW1lc190byA9ICdyaXNrJywgdmFsdWVzX3RvID0gJ3ZhbHVlJykgJT4lCiAgbXV0YXRlKHJpc2tfZmFjdG9yID0gYXNfZmFjdG9yKHJpc2spLCB2YWx1ZXNfY2xlYW5lZCA9IGlmX2Vsc2UoaXMuaW5maW5pdGUodmFsdWUpLCAxOCwgdmFsdWUpKSAlPiUKICBtdXRhdGUocmVsYXRpdmVfcmlza19jbGVhbmVkID0gaWZfZWxzZShpcy5uYW4odmFsdWVzX2NsZWFuZWQpLCAxLCB2YWx1ZXNfY2xlYW5lZCkpICU+JQogIG11dGF0ZShyZWxhdGl2ZV9yaXNrX2NsZWFuZWRfdHJ1bmNhdGVkYXQyID0gaWZfZWxzZSgocmVsYXRpdmVfcmlza19jbGVhbmVkKSA+IDIsIDIsIHJlbGF0aXZlX3Jpc2tfY2xlYW5lZCkpICU+JQogIHNlbGVjdChsYXRfYm94LCBsbmdfYm94LCBoYWxmX3llYXIsIHJpc2tfZmFjdG9yLCByZWxhdGl2ZV9yaXNrX2NsZWFuZWQsIHJlbGF0aXZlX3Jpc2tfY2xlYW5lZF90cnVuY2F0ZWRhdDIpICU+JQogIGdncGxvdCgpICsKICBnZW9tX3NmKGRhdGEgPSB3b3JsZF9tYXApICsKICBnZW9tX3RpbGUobWFwcGluZyA9IGFlcyh4ID0gbG5nX2JveCwgeSA9IGxhdF9ib3gsIGZpbGwgPSByZWxhdGl2ZV9yaXNrX2NsZWFuZWRfdHJ1bmNhdGVkYXQyLCB3aWR0aCA9IHJlc3kpKSArCiAgc2NhbGVfZmlsbF9ncmFkaWVudDIobWlkcG9pbnQgPSAxLCBsaW1pdHMgPSBjKDAsIDIpLCBsb3cgPSAnY3lhbicsIGhpZ2ggPSAncmVkJykgKwogIGZhY2V0X2dyaWQocm93cyA9IHZhcnMocmlza19mYWN0b3IpLCBjb2xzID0gdmFycyhoYWxmX3llYXIpKSsKICBnZ3RpdGxlKCJIYWxmIHllYXIgUmVsYXRpdmUgcmlzayBwbG90IHVzaW5nIGNhbGN1bGF0aW9ucyBvZiB0aGUgZm9ybSBbe251bV9kaXNhc3RlcnNfcG9zaXRpdmVfd2V0IC8gbnVtX21vbnRoc19wb3NpdGl2ZX0gLyB7bnVtX2Rpc2FzdGVyc19ub19ldmVudF93ZXQgLyBudW1fbW9udGhzX25vX2V2ZW50fV0iKQogIAogIAoKYGBgCgojIyBEcnkgRGlzYXN0ZXJzCgpgYGB7cn0KcmVzeSA8LSAyLjUKCmVtZGF0X2h5ZHJvbG9naWNhbF9lbnNvICU+JQogIGZpbHRlcihkcnkpICU+JQogIG11dGF0ZShsYXRfYm94ID0gKGFzLmludGVnZXIobGF0KSAlLyUgcmVzeSkgKiByZXN5ICwgbG5nX2JveCA9IChhcy5pbnRlZ2VyKGxuZykgJS8lIHJlc3kpICogcmVzeSkgJT4lCiAgZ3JvdXBfYnkoYERpcyBOb2AsIGxhdF9ib3gsIGxuZ19ib3gpICU+JQogIHN1bW1hcmlzZShkaXNhc3Rlcl90eXBlID0gZmlyc3QoYERpc2FzdGVyIFR5cGVgKSkgJT4lCiAgZ3JvdXBfYnkoZGlzYXN0ZXJfdHlwZSwgbGF0X2JveCwgbG5nX2JveCkgJT4lCiAgc3VtbWFyaXNlKGNvdW50eSA9IG4oKSkgJT4lCiAgZmlsdGVyKGNvdW50eSA+IDApICU+JQogIGdncGxvdCgpICsKICBnZW9tX3NmKGRhdGEgPSB3b3JsZF9tYXApICsKICBnZW9tX3RpbGUobWFwcGluZyA9IGFlcyh4ID0gbG5nX2JveCwgeSA9IGxhdF9ib3gsIGZpbGwgPSBjb3VudHksIHdpZHRoID0gcmVzeSkpICsKICBzY2FsZV9maWxsX2NvbnRpbnVvdXModHlwZT0iZ3JhZGllbnQiLCBsb3cgPSAid2hpdGUiLCBoaWdoID0gInJlZCIpICsKICBmYWNldF9ncmlkKHJvd3MgPSB2YXJzKGRpc2FzdGVyX3R5cGUpKSsKICBnZ3RpdGxlKCJEcnkgZGlzYXN0ZXIgdHlwZXMgYXJvdW5kIHRoZSB3b3JsZCIpCiAgCiAgCiAgCmBgYAoKYGBge3J9CmVtZGF0X2h5ZHJvbG9naWNhbF9lbnNvICU+JQogIGZpbHRlcihkcnkpICU+JQogIG11dGF0ZShsYXRfYm94ID0gKGFzLmludGVnZXIobGF0KSAlLyUgcmVzeSkgKiByZXN5ICwgbG5nX2JveCA9IChhcy5pbnRlZ2VyKGxuZykgJS8lIHJlc3kpICogcmVzeSkgJT4lCiAgZ3JvdXBfYnkoYERpcyBOb2ApICU+JQogIHN1bW1hcmlzZShkaXNhc3Rlcl90eXBlID0gZmlyc3QoYERpc2FzdGVyIFR5cGVgKSkgJT4lCiAgZ3JvdXBfYnkoZGlzYXN0ZXJfdHlwZSkgJT4lCiAgc3VtbWFyaXNlKGNvdW50eSA9IG4oKSkKCmBgYAoKYGBge3J9CmVtZGF0X2h5ZHJvbG9naWNhbF9lbnNvICU+JQogIGZpbHRlcihkcnkpICU+JQogIGZpbHRlcighaXMubmEoRXZlbnQpKSAlPiUKICBtdXRhdGUobGF0X2JveCA9IChhcy5pbnRlZ2VyKGxhdCkgJS8lIHJlc3kpICogcmVzeSAsIGxuZ19ib3ggPSAoYXMuaW50ZWdlcihsbmcpICUvJSByZXN5KSAqIHJlc3kpICU+JQogIGdyb3VwX2J5KGBEaXMgTm9gLCBFdmVudCkgJT4lCiAgc3VtbWFyaXNlKGRpc2FzdGVyX3R5cGUgPSBmaXJzdChgRGlzYXN0ZXIgVHlwZWApKSAlPiUKICBnZ3Bsb3QoKSArCiAgZ2VvbV9iYXIobWFwcGluZyA9IGFlcyh4ID0gZGlzYXN0ZXJfdHlwZSwgc3RhdCA9ICJjb3VudCIpKSArCiAgZmFjZXRfZ3JpZCh+RXZlbnQpCgpgYGAKCmBgYHtyfQplbWRhdF9oeWRyb2xvZ2ljYWxfZW5zbyAlPiUKICBmaWx0ZXIoZHJ5KSAlPiUKICBmaWx0ZXIoIWlzLm5hKEV2ZW50KSkgJT4lCiAgbXV0YXRlKGxhdF9ib3ggPSAoYXMuaW50ZWdlcihsYXQpICUvJSByZXN5KSAqIHJlc3kgLCBsbmdfYm94ID0gKGFzLmludGVnZXIobG5nKSAlLyUgcmVzeSkgKiByZXN5KSAlPiUKICBncm91cF9ieShgRGlzIE5vYCwgRXZlbnQpICU+JQogIHN1bW1hcmlzZShkaXNhc3Rlcl90eXBlID0gZmlyc3QoYERpc2FzdGVyIFR5cGVgKSkgJT4lCiAgZ2dwbG90KCkgKwogIGdlb21fYmFyKG1hcHBpbmcgPSBhZXMoeCA9IEV2ZW50LCBzdGF0ID0gImNvdW50IikpICsKICBmYWNldF9ncmlkKH5kaXNhc3Rlcl90eXBlKQoKYGBgCiMjIExvb2tpbmcgYXQgRU5TTyBWYWx1ZQoKYGBge3J9CmVtZGF0X2h5ZHJvbG9naWNhbF9lbnNvICU+JQogIGdyb3VwX2J5KGBEaXMgTm9gKSAlPiUKICBzdW1tYXJpemUoZGlzYXN0ZXJfdHlwZSA9IGZpcnN0KGBEaXNhc3RlciBUeXBlYCksIGxhdCA9IG1lYW4obGF0KSwgbG5nID0gbWVhbihsbmcpLCBlbnNvX3ZhbHVlID0gbWVhbihlbnNvX1ZhbHVlKSwgRXZlbnQgPSBmaXJzdChFdmVudCksIGRyeSA9IGZpcnN0KGRyeSksIHdldCA9IGZpcnN0KHdldCkpICU+JQogIGdncGxvdCgpICsKICBnZW9tX2hpc3RvZ3JhbShtYXBwaW5nID0gYWVzKHggPSBlbnNvX3ZhbHVlKSwgYmlud2lkdGggPSAwLjEpIAoKYGBgCgpgYGB7cn0KZW1kYXRfaHlkcm9sb2dpY2FsX2Vuc28gJT4lCiAgZmlsdGVyKCFpcy5uYShgRGlzYXN0ZXIgVHlwZWApKSAlPiUKICBncm91cF9ieShgRGlzIE5vYCkgJT4lCiAgc3VtbWFyaXplKGRpc2FzdGVyX3R5cGUgPSBmaXJzdChgRGlzYXN0ZXIgVHlwZWApLCBsYXQgPSBtZWFuKGxhdCksIGxuZyA9IG1lYW4obG5nKSwgZW5zb192YWx1ZSA9IG1lYW4oZW5zb19WYWx1ZSksIEV2ZW50ID0gZmlyc3QoRXZlbnQpLCBkcnkgPSBmaXJzdChkcnkpLCB3ZXQgPSBmaXJzdCh3ZXQpKSAlPiUKICBnZ3Bsb3QoKSArCiAgZ2VvbV9oaXN0b2dyYW0obWFwcGluZyA9IGFlcyh4ID0gZW5zb192YWx1ZSksIGJpbndpZHRoID0gMC4xKSArCiAgZmFjZXRfZ3JpZCh+ZGlzYXN0ZXJfdHlwZSkKCgpgYGAKIyMgQ3JlYXRlIERhdGEgYXMgTmV0Q0RGCgpgYGB7cn0KcmVzeSA8LSAyLjUKCmRmX3RvX2JlX3NwYXRpYWxpemVkIDwtIGVtZGF0X2h5ZHJvbG9naWNhbCAlPiUKICBtdXRhdGUobGF0X2JveCA9IChhcy5pbnRlZ2VyKGxhdCkgJS8lIHJlc3kpICogcmVzeSAsIGxuZ19ib3ggPSAoYXMuaW50ZWdlcihsbmcpICUvJSByZXN5KSAqIHJlc3kpICU+JQogIG11dGF0ZShtb250aF9udW1iZXIgPSAoZW5kX3llYXIgKiAxMikgKyBlbmRfbW9udGgpICU+JQogIGdyb3VwX2J5KGxhdF9ib3gsIGxuZ19ib3gsIG1vbnRoX251bWJlciwgYERpcyBOb2AsIGBEaXNhc3RlciBUeXBlYCkgJT4lCiAgc3VtbWFyaXplKG51bV9tb250aHNfZGlzYXN0ZXIgPSBtZWFuKG51bV9tb250aHNfZGlzYXN0ZXIpKSAlPiUKICBncm91cF9ieShsYXRfYm94LCBsbmdfYm94LCBtb250aF9udW1iZXIsIGBEaXNhc3RlciBUeXBlYCkgJT4lCiAgc3VtbWFyaXplKG51bV9kaXNhc3Rlcl9tb250aHMgPSBzdW0obnVtX21vbnRoc19kaXNhc3RlcikpICU+JQogIGZpbHRlcighaXMubmEobGF0X2JveCkpCgpgYGAKCmBgYHtyfQoKZGZfdG9fYmVfc3BhdGlhbGl6ZWQyICU+JQogIHdyaXRlX2Nzdigifi9EZXNrdG9wL3Byb2plY3RzL2VtZGF0X3Byb2ovZGF0YS9kZl90b19iZV9zcGF0aWFsaXplZDIuY3N2IikKCiMjIENvbnZlcnNpb24gdG8gYmUgZG9uZSBpbiBwYW5kYXMgaW4gcHl0aG9uCgpgYGAKYGBge3J9CgpkZl90b19iZV9zcGF0aWFsaXplZCAlPiUKICBtdXRhdGUobW9udGhfb2ZfeWVhciA9IG1vbnRoX251bWJlciAlJSAxMikgJT4lCiAgbXV0YXRlKHllYXIgPSAobW9udGhfbnVtYmVyIC0gbW9udGhfb2ZfeWVhcikgLyAxMikgJT4lCiAgYXJyYW5nZShtb250aF9udW1iZXIpCgoKYGBgCmBgYHtyfQoKZW1kYXRfaHlkcm9sb2dpY2FsX2Vuc28gJT4lCiAgYXJyYW5nZSgtMSAqIG51bV9tb250aHNfZGlzYXN0ZXIpCgpgYGAKCmBgYHtyfQplbnNvX3ZhbHVlc3kgPC0gZW5zb19kYXRhICU+JQogIG11dGF0ZShtb250aF9udW1iZXIgPSAoWWVhciAqIDEyKSArIE1vbnRoTnVtLCBlbnNvX3ZhbHVlID0gVmFsdWUpICU+JQogIHNlbGVjdChtb250aF9udW1iZXIsIGVuc29fdmFsdWUpCgpuZXdfZW1kYXRfZGF0YSA8LSBlbWRhdF9oeWRyb2xvZ2ljYWwyICU+JQogIG11dGF0ZShzdGFydF9tb250aF9udW1iZXIgPSBgU3RhcnQgTW9udGhgICsgKDEyICogc3RhcnRfeWVhcikpICU+JQogIG11dGF0ZShlbmRfbW9udGhfbnVtYmVyID0gZW5kX21vbnRoICsgKDEyICogZW5kX3llYXIpKSAlPiUKICByb3d3aXNlKCkgJT4lCiAgbXV0YXRlKG1vbnRoaWVzID0gbGlzdCh0aWJibGUobW9udGhfbnVtYmVyID0gc3RhcnRfbW9udGhfbnVtYmVyOmVuZF9tb250aF9udW1iZXIpKSkgJT4lCiAgZmlsdGVyKG51bV9tb250aHNfZGlzYXN0ZXIgPiAyKSAlPiUKICB1bm5lc3QoY29scyA9IG1vbnRoaWVzKSAlPiUKICBtdXRhdGUobGF0X2JveCA9IChhcy5pbnRlZ2VyKGxhdCkgJS8lIHJlc3kpICogcmVzeSAsIGxuZ19ib3ggPSAoYXMuaW50ZWdlcihsbmcpICUvJSByZXN5KSAqIHJlc3kpICU+JQogIGdyb3VwX2J5KGxhdF9ib3gsIGxuZ19ib3gsIG1vbnRoX251bWJlciwgYERpcyBOb2AsIGBEaXNhc3RlciBUeXBlYCkgJT4lCiAgc3VtbWFyaXplKG1lYW5fbW9udGhzID0gbWVhbihudW1fbW9udGhzX2Rpc2FzdGVyKSkgJT4lCiAgZ3JvdXBfYnkobGF0X2JveCwgbG5nX2JveCwgbW9udGhfbnVtYmVyLCBgRGlzYXN0ZXIgVHlwZWApICU+JQogIHN1bW1hcml6ZShkaXNhc3RlciA9IChzdW0obWVhbl9tb250aHMpID4gMCkpICU+JQogIGZpbHRlcighaXMubmEobGF0X2JveCkpIAoKZGZfdG9fYmVfc3BhdGlhbGl6ZWQyIDwtIG5ld19lbWRhdF9kYXRhCgpuZXdfZW5zb19kYXRhX29uaSA8LSByZWFkX3Rzdigifi9EZXNrdG9wL29uaV9lbnNvLnRzdiIpCgpuZXdfZW5zb19kYXRhX29uaSAlPiUKICBwaXZvdF9sb25nZXIoY29scyA9IGNvbG5hbWVzKG5ld19lbnNvX2RhdGFfb25pKVstMV0sCiAgICAgICAgICAgICAgIG5hbWVzX3RvID0gIk1vbnRoIiwKICAgICAgICAgICAgICAgdmFsdWVzX3RvID0gImVuc29fb25pX3ZhbHVlIikgJT4lCiAgcm93d2lzZSgpICU+JQogIG11dGF0ZShtb250aF9udW0gPSBtb250aF90ZXh0X3RvX251bShNb250aCkpICU+JQogIG11dGF0ZShtb250aF9udW1iZXIgPSBtb250aF9udW0gKyAoMTIgKiBZZWFyKSkgJT4lCiAgd3JpdGVfY3N2KCJ+L0Rlc2t0b3AvcHJvamVjdHMvZW1kYXRfcHJvai9kYXRhL2Vuc29fZGF0YV91cGRhdGVkXzZfOV8yMy5jc3YiKQogIAoKbGlzdHkgPC0gbGlzdCgpCmxpc3R5WyJESkYiXSA9IDEKbGlzdHlbIkpGTSJdID0gMgpsaXN0eVsiRk1BIl0gPSAzCmxpc3R5WyJNQU0iXSA9IDQKbGlzdHlbIkFNSiJdID0gNQpsaXN0eVsiTUpKIl0gPSA2Cmxpc3R5WyJKSkEiXSA9IDcKbGlzdHlbIkpBUyJdID0gOApsaXN0eVsiQVNPIl0gPSA5Cmxpc3R5WyJTT04iXSA9IDEwCmxpc3R5WyJPTkQiXSA9IDExCmxpc3R5WyJOREoiXSA9IDEyCgptb250aF90ZXh0X3RvX251bSA8LSBmdW5jdGlvbih4KSBsaXN0eVtbeF1dCgpuZXdfZW1kYXRfZGF0YSAlPiUKICB3cml0ZV9jc3YoIn4vRGVza3RvcC9wcm9qZWN0cy9lbWRhdF9wcm9qL2RhdGEvZW1kYXRfZGZfdG9fYmVfc3BhdGlhbGl6ZWRfdXBkYXRlZF82XzlfMjMuY3N2IikKCgoKICAKCmBgYAo=